package leetcode.字符串;

/**
 * 有效数字
 * todo 自动状态机
 */
public class Test65有效数字 {

    /*
      例子： -53.5e+93，在数学上把 e 之前的部分叫做 a
      a这个部分在 e 之前，正负号必须在 a 之前且只能出现一种&一个，小数点必须在 a 里面
      a 之后可以没有任何数据了，有的话必须是 e/E ，e 之后是整数，该整数可以有正负号，不能出现小数

     */
    public static boolean isNumber(String s) {
        // 清除首尾空格
        s = s.trim();
        boolean pointSeen = false; // 标记是否出现过小数点
        boolean eSeen = false; // 标记是否出现过 e
        boolean numberSeen = false; // 标记e之前是否有数字
        boolean numberAfterE = true; // 标记e之后是否出现了数字

        // 遍历整个字符串
        for (int i = 0; i < s.length(); i++) {
            // 1. 判断当前遍历的字符是否是数字，是的话要在 0~9 之间
            if ('0' <= s.charAt(i) && s.charAt(i) <= '9') {
                numberSeen = true;
                numberAfterE = true;
            }
            // 2. 不是数字则分别检查其是否是正负号、小数点、e/E
            else if (s.charAt(i) == '.') {
                // 2.1 若是小数点，则不能出现在 e 之后以及其他小数点之后（小数点不能出现多次）
                if (eSeen || pointSeen) {
                    return false;
                }
                pointSeen = true;
            } else if (s.charAt(i) == 'e') {
                // 2.2 若是 e 的话，则之前不能出现过 e 且 e 之前出现过数字
                if (eSeen || !numberSeen) {
                    return false;
                }
                numberAfterE = false;
                eSeen = true;
            } else if (s.charAt(i) == '-' || s.charAt(i) == '+') {
                // 2.3 若是正负号的话，正负号必须是 a 部分的第一个字符或者 e 后面的第一个字符
                if (i != 0 && s.charAt(i - 1) != 'e') {
                    return false;
                }
            }
            // 3. 出现非法字符直接返回 false
            else {
                return false;
            }
        }
        return numberSeen && numberAfterE;
    }

    // *[+-]?([0-9]+(\.[0-9]*)?|\.[0-9]+)(e[+-]?[0-9]+)? *$
    public static boolean isNumber2(String s) {
        s = s.trim();
        if (s.matches("^*[+-]?([0-9]+(\\.[0-9]*)?|\\.[0-9]+)(e[+-]?[0-9]+)? *$")) {
            return true;
        } else {
            return false;
        }
    }

    public static void main(String[] args) {
        System.out.println(isNumber("2.2e10"));
        System.out.println(isNumber2("2.2e10"));
    }
}
